home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 41 / Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso / -seriously_amiga- / cd-rom / acdb / src / acdb_cddb.e < prev    next >
Text File  |  1999-04-28  |  15KB  |  555 lines

  1. OPT MODULE,OSVERSION=37
  2. OPT PREPROCESS,REG=5
  3.  
  4.  
  5. /*
  6.  *-- AutoRev header do NOT edit!!
  7.  *
  8.  *   Project         :   ACDB (AMIGA CD Base) - program obsîugujâcy CDDB
  9.  *   File            :   acdb_cddb.e
  10.  *   Description     :   obsîuga CDDB via HTTP/GET
  11.  *   Copyright       :   ©1999, Piotr Gapiïski
  12.  *   Author          :   Piotr Gapiïski
  13.  *   Creation Date   :   20.03.99
  14.  *   Current version :   1.0
  15.  *   Translator      :   AmigaE v3.3a
  16.  *
  17.  *-- REVISION HISTORY
  18.  *
  19.  *   1.0 (20.03.99)
  20.  *    o   w przypadku inexact matches i multiple matches zapisywane sâ wszystkie
  21.  *        istniejâce opisy pîyty przy czym pierwszy zapisywany jest z normalnâ
  22.  *        nazwâ (CDID) a pozostaîe z koïcówkami bëdâcymi numerem kopii
  23.  *    o   w przypadku gdy bîëdów poîâczenia nie wpîywajâcych na ogólnâ pracë programu
  24.  *        (takich jak np. brak ûâdanego opisu pîyty w bazie czy niewîaôciwy identyfikator pîyty0
  25.  *        odpowiedni plik z katalogu TEMP zostanie zmieniony na IDxxxxxxxx.przyczyna_bîëdu
  26.  *    o   wsparcie dla arexx'a (w tym i dla zwrotnych kodów bîëdów)
  27.  *
  28.  *   0.5 (15.01.99)
  29.  *    o   zniesiony limit dîugoôci znaków w wierszu opisu (60 znaków)
  30.  *    o   nowy parser wiadomoôci odebranych
  31.  *    o   moûliwoôê przerwania odczytu danych co kaûde 100 bajtów
  32.  *
  33.  *   0.4 (03.01.99)
  34.  *    o   zwiëkszone bufory na komendy wysyîane do CDDB (do 400 bajtów)
  35.  *    o   identyfikator pîyty (cdid) MUSI byê 8 cyfrowy (z ewentualnymi zerami wiodâcymi)
  36.  *        najprawdopodobniej to byîo przyczynâ 'zawieszania' sië programu
  37.  *
  38.  *   0.3 (28.12.98)
  39.  *    o   nowy parser wiadomoôci odebranych
  40.  *    o   obsîuga 'inexact matches'
  41.  *    o   protokóî zgodny z wersjâ 4 (obsîuga kodów QUERY: 211 i 210)
  42.  *    o   zapisywanie plików jest teraz zgodne z SCDP
  43.  *
  44.  *   0.2 (26.12.98)
  45.  *    o   progresywne odczytywanie danych nadchodzâcych z serwera
  46.  *        odczytywanie trwa tak dîugo, aû Recv() zwróci 0 pobranych bajtów
  47.  *    o   poîâczenia sâ tylu KEEPALIVE dziëki czemu pomiëdzy poszczególnymi wywoîaniami
  48.  *        Send() poîâczenie nie jest koïczone
  49.  *    o   tytuî pîyty (satandardowo w postaci TYTUÎ/AUTOR) jest teraz rozbity na dwie linie
  50.  *
  51.  *   0.1 (22.12.98)
  52.  *    o   pierwsza wersja (BETA)
  53.  *        na podstawie @(#)cddb.howto 1.27 (98/12/09)
  54.  *
  55.  *-- REV_END --*
  56.  */
  57.  
  58.  
  59.   MODULE 'tools/easygui'
  60.   MODULE 'intuition/intuition','intuition/screens','exec/nodes','exec/lists','dos/dos'
  61.   MODULE 'utility/tagitem','libraries/gadtools','bsdsocket','icon','tools/file','amigalib/lists'
  62.   MODULE 'afc/parser','afc/explain_exception'
  63.   MODULE '*acdb_debug','*acdb_cd','*acdb_net','*acdb_gui', '*acdb_arexx'
  64.  
  65.  
  66.   #ifdef DEBUG
  67.     MODULE 'tools/debug'
  68.     #define D(a,b) kputfmt(a,b)
  69.   #endif
  70.   #ifndef DEBUG
  71.     #define D(a,b)
  72.   #endif
  73.  
  74.   #define CLIENTINFO 'narg+polbox.com+acdb+1.0&proto=4'
  75.   CONST BUFFSIZE = 10240
  76.   OBJECT match OF ln
  77.     category      :PTR TO CHAR      ->- kategoria pîyty
  78.     cdid          :LONG             ->- identyfikator
  79.   ENDOBJECT
  80.  
  81.   EXPORT DEF tt_disks, tt_temp, tt_cddbhost, tt_cddbport,
  82.              tt_cdtime, tt_tracktime
  83.  
  84.  
  85.  
  86. EXPORT PROC cddb(cd:PTR TO cdinfo, arexx=NIL:PTR TO arxArgs) HANDLE
  87.  
  88.   ->-
  89.   ->- procedura pobierajâca z CDDB opis ûâdanej pîyty kompaktowej
  90.   ->- 1. jeûeli opis istnieje, zostanie zapisany w katalogu DISKS, a odpowiedni
  91.   ->-    plik z katalogu TEMP zostanie skasowany
  92.   ->- 2. jeûeli opis nie istnieje to plik z katalogu TEMP zostanie zmieniony na
  93.   ->-    if.not_found
  94.   ->- procedura zwraca TRUE/FALSE
  95.   ->-
  96.  
  97.   DEF matches:lh, match:PTR TO match, code, rc, error=NIL
  98.   DEF i
  99.  
  100.  
  101.   newList(matches)
  102.   D('[CDDB] querying database\n', NIL)
  103.  
  104.   rc, code := query(cd, matches)
  105.   IF (rc)
  106.  
  107.     ->-
  108.     ->- przejdú do pobierania pîytki
  109.     ->-
  110.  
  111.     i := 0
  112.     WHILE (match := RemHead(matches))
  113.  
  114.       ->-
  115.       ->- pobieranie wszystkich moûliwych opisów pîytek
  116.       ->- zwolnij niepotrzebne juû zasoby
  117.       ->-
  118.  
  119.       D('[CDDB] search cddb for \s\n', [match.name, NIL])
  120.       rc, code := description(cd, i++, match)
  121.       IF (match) THEN freematch(match)
  122.       EXIT (rc = FALSE)
  123.     ENDWHILE
  124.   ENDIF
  125.  
  126.   IF (rc = FALSE)
  127.     SELECT code
  128.  
  129.       ->-
  130.       ->- obsîuga bîëdów
  131.       ->- czëôê z nich powoduje zmianë nazwy pliku CDID w katalogu TEMP
  132.       ->-
  133.  
  134.       CASE 202;   renametemp(cd, '.not found')
  135.       CASE 401;   renametemp(cd, '.not found')
  136.       CASE 403;   renametemp(cd, '.corrupt')
  137.       CASE 501;   renametemp(cd, '.invalid')
  138.       CASE 402;   error := 'CDDB server error (402)!\nPlease use other CDDB host'
  139.       CASE 403;   error := 'CDDB database entry is corrupt!\nPlease try again later'
  140.       CASE 409;   error := 'CDDB no handshake!\nPlease try again later'
  141.       CASE 500;   error := 'Command syntax error!\nSubmited command is corrupt, please\ncontact with ACDB author'
  142.     DEFAULT
  143.  
  144.       ->-
  145.       ->- rozróûnienie bîëdów generowanych na podstawie kodu zwrotnego CDDB
  146.       ->- a tych generowanych wewnâtrz procedury odbioru
  147.       ->-
  148.  
  149.       error := IF (code > 200)AND(code < 600) THEN 'General CDDB error!\nPlease use other CDDB server' ELSE code
  150.     ENDSELECT
  151.     IF (error) THEN Raise(error)
  152.   ENDIF
  153.   RETURN TRUE
  154.  
  155. EXCEPT
  156.   freeallmatches(matches)
  157.   IF (exception)
  158.     D('[CDDB] error \s\n', [exception, NIL])
  159.  
  160.     IF (arexx)
  161.  
  162.       ->-
  163.       ->- procedura zostaîa wywoîana z poziomu arexx'a wiëc wszelkie komunikaty
  164.       ->- o bîëdach wîaônie tam bëdâ przekazane
  165.       ->-
  166.  
  167.       arexx.err := exception
  168.       arexx.rclong := 0
  169.     ELSE
  170.  
  171.       ->-
  172.       ->- domyôlnie bëdzie wyôwietlony requester
  173.       ->-
  174.  
  175.       guiInformUser(exception, NIL, exceptioninfo)
  176.     ENDIF
  177.   ENDIF
  178. ENDPROC FALSE
  179.  
  180.  
  181.  
  182. EXPORT PROC renametemp(cd, suffix)
  183.  
  184.   ->-
  185.   ->- procedura zamieniajâca nazwë wybranego pliku cdid (z katalogu TEMP)
  186.   ->- przez dodanie koïcówki suffix
  187.   ->- zwraca kod bîëdów procedury DOS/Rename
  188.   ->-
  189.  
  190.   DEF in[255]:STRING, out[255]:STRING
  191.  
  192.  
  193.   StrCopy(in, tt_temp)
  194.   AddPart(in, cdFileId(cd), 255)
  195.   StrCopy(out, in)
  196.   StrAdd(out, suffix)
  197. ENDPROC Rename(in, out)
  198.  
  199.  
  200.  
  201.     ->-
  202.     ->- prywatne
  203.     ->- procedury wspomagajâce pobieranie opisów pîyt z internetu
  204.     ->-
  205.  
  206.  
  207.  
  208. PROC query(cd, matches:PTR TO lh) HANDLE
  209.  
  210.   ->-
  211.   ->- zapytanie o kategorie pîyty
  212.   ->- zwraca 1: TRUE/FALSE, 2: kod CDDB/kod bîëdu
  213.   ->- w przypadku sukcesu bëdzie to TRUE/CDDB a w przypadku poraûki FALSE/CDDB lub
  214.   ->- FALSE/ERROR
  215.   ->-
  216.  
  217.   DEF sd, cmd[400]:STRING, tmp[400]:STRING, tracks
  218.   DEF buff:PTR TO CHAR, bytes, code, x, rc=FALSE
  219.  
  220.   ->-
  221.   ->- budowanie zapytania
  222.   ->-
  223.  
  224.   buff := New(BUFFSIZE)
  225.   D('[QUERY] connect to \s:\d\n', [tt_cddbhost, tt_cddbport, NIL])
  226.   IF (sd := netConnect(tt_cddbhost, tt_cddbport))<0 THEN Raise('Cannot resolve (cddb) host address!\nIncorrect address or TCP/IP stack not running')
  227.  
  228.  
  229.   D('[QUERY] compute cddb query\n', NIL)
  230.   tracks := cdTracks(cd)
  231.   stringFmt(tmp, '/~cddb/cddb.cgi?cmd=cddb+query+%08.8lx+%ld', [cdId(cd), tracks, NIL])
  232.   StrCopy(cmd, tmp)
  233.   FOR x := 0 TO (tracks - 1) DO StrAdd(cmd, stringFmt(tmp, '+%ld', [cdTrackOffset(cd, x), NIL]))
  234.   stringFmt(tmp, '+%ld&hello=%s', [cdTime(cd), CLIENTINFO, NIL])
  235.   StrAdd(cmd, tmp)
  236.  
  237.   ->-
  238.   ->- wysyîanie zapytania do bazy danych
  239.   ->-
  240.  
  241.   D('[QUERY] sending query\n', NIL)
  242.   IF netSendcmd(sd, cmd)=FALSE THEN Raise('Connection broken!\nPlease try again later')
  243.   bytes := netReceive(sd, buff, BUFFSIZE)
  244.   IF (bytes = 0) THEN Raise('Cannot read data from host\nAborted due to user request')
  245.  
  246.   ->-
  247.   ->- tworzenie listy wszystkich opisów pîytek pasujâcych do wzorca
  248.   ->-
  249.  
  250.   code := Val(buff)
  251.   rc := findmatches(matches, buff, bytes)
  252.   D('[QUERY] code \d\n', [code, NIL])
  253.   D('[QUERY] matches \s FOUND\n', [IF (rc) THEN '' ELSE 'NOT', NIL])
  254.  
  255. EXCEPT DO
  256.   IF (buff) THEN Dispose(buff)
  257.   IF (sd >= 0) THEN CloseSocket(sd)
  258.   IF (exception)
  259.     rc := FALSE
  260.     code := exception
  261.     D('[QUERY] error \s\n', [exception, NIL])
  262.   ENDIF
  263. ENDPROC rc, code
  264.  
  265.  
  266.  
  267. PROC description(cd, copy, match:PTR TO match) HANDLE
  268.  
  269.   ->-
  270.   ->- zapytanie o opis pîyty okreôlonej przez cd oraz strukturë match
  271.   ->- zwraca 1: TRUE/FALSE, 2: kod CDDB/kod bîëdu
  272.   ->- w przypadku sukcesu bëdzie to TRUE/CDDB a w przypadku poraûki FALSE/CDDB lub
  273.   ->- FALSE/ERROR
  274.   ->-
  275.  
  276.   DEF cmd[400]:STRING
  277.   DEF sd, buff:PTR TO CHAR, code, bytes, rc=FALSE
  278.  
  279.   buff := New(BUFFSIZE)
  280.  
  281.   D('[DESCRIPTION] connect to \s:\d\n', [tt_cddbhost, tt_cddbport, NIL])
  282.   IF (sd := netConnect(tt_cddbhost, tt_cddbport))<0 THEN Raise('Cannot resolve (cddb) host address!\nIncorrect address or TCP/IP stack not running')
  283.   stringFmt(cmd, '/~cddb/cddb.cgi?cmd=cddb+read+%s+%08.8lx&hello=%s', [match.category, match.cdid, CLIENTINFO, NIL])
  284.  
  285.   D('[DESCRIPTION] send cmd\n', NIL)
  286.   IF netSendcmd(sd, cmd)=FALSE THEN Raise('Connection broken!\nPlease try again later')
  287.  
  288.   D('[DESCRIPTION] receive description\n', NIL)
  289.   bytes := netReceive(sd, buff, BUFFSIZE)
  290.   IF (bytes = 0) THEN Raise('Cannot read data from host\nAborted due to user request')
  291.  
  292.  
  293.   code := Val(buff)
  294.   D('[DESCRIPTION] code \d\n', code)
  295.   rc := IF (code = 210) THEN save(cd, copy, buff, bytes) ELSE FALSE
  296.  
  297. EXCEPT DO
  298.   IF (buff) THEN Dispose(buff)
  299.   IF (sd >= 0) THEN CloseSocket(sd)
  300.   IF (exception)
  301.     rc := FALSE
  302.     code := exception
  303.     D('[DESCRIPTION] error \s\n', [exception, NIL])
  304.   ENDIF
  305. ENDPROC rc, code
  306.  
  307.  
  308.  
  309. PROC save(cd, copy, buff:PTR TO CHAR, bytes) HANDLE
  310.  
  311.   ->-
  312.   ->- zapisywanie opisu pîytki na dysk w formacie SCDP
  313.   ->- copy to kolejny numer kopii danego opisu pîyty ale jeûeli copy = 0
  314.   ->- to suffix nie zostanie zapisany
  315.   ->-
  316.  
  317.   DEF list, listlen, path[255]:STRING
  318.   DEF title:PTR TO CHAR, x, tmp[400]:STRING
  319.   DEF pos, handle=NIL, mm, ss
  320.  
  321.  
  322.   list := stringsinfile(buff, bytes, countstrings(buff, bytes))
  323.   listlen := ListLen(list)
  324.  
  325.   ->-
  326.   ->- okreôlnenie nazwy zapisywanego pliku w konwencji
  327.   ->- ID.x
  328.   ->- gdzie x to kolejny numer kopii
  329.   ->-
  330.  
  331.   StrCopy(tmp, tt_disks)
  332.   AddPart(tmp, cdFileId(cd), 255)
  333.   stringFmt(path, IF (copy > 0) THEN '%s.%ld' ELSE '%s', [tmp, copy, NIL])
  334.   D('[SAVE] file \s\n', [path, NIL])
  335.   IF (handle := Open(path, MODE_NEWFILE))=NIL THEN Raise('Cannot write CD description!\nCheck all TOOLTYPES passed to the program')
  336.  
  337.   ->-
  338.   ->- zapis danych do pliku o nazwie NAME
  339.   ->- tytuî pîyty trzeba przeksztaîciê z formatu "AUTOR / TYTUÎ" na "AUTOR\nTYTUÎ"
  340.   ->-
  341.  
  342.   IF (title := FindToolType(list, 'DTITLE'))
  343.     title[StrLen(title) - 1] := "\0"
  344.  
  345.     ->-
  346.     ->- znajdú znak rozdzielajâcy
  347.     ->-
  348.  
  349.     IF (pos := InStr(title, '/'))
  350.  
  351.       ->-
  352.       ->- podziel na tytuî i autora
  353.       ->-
  354.  
  355.       title[pos - 1] := "\0"
  356.       D('[SAVE] author \s\n', [title, NIL])
  357.       Write(handle, title, StrLen(title)); Write(handle, '\n', STRLEN)
  358.  
  359.       IF (tt_cdtime)
  360.  
  361.         ->-
  362.         ->- dodaj do opisu caîkowity czas trwania pîyty
  363.         ->-
  364.  
  365.         ss, mm := Mod(cdTime(cd), 60)
  366.         stringFmt(tmp, '%s [%ld:%02.2ld]\n', [(title + pos + 2), mm, ss, NIL])
  367.       ELSE
  368.  
  369.         ->-
  370.         ->- tylko autor pîyty
  371.         ->-
  372.  
  373.         stringFmt(tmp, '%s\n', [(title + pos + 2), NIL])
  374.       ENDIF
  375.  
  376.  
  377.       D('[SAVE] album \s', [tmp, NIL])
  378.       Write(handle, tmp, StrLen(tmp))
  379.     ENDIF
  380.   ELSE
  381.  
  382.     ->-
  383.     ->- bîâd, opis pîyty nie zawiera tytuîu
  384.     ->- skasuj dopiero co otwarty plik
  385.     ->-
  386.  
  387.     Close(handle)
  388.     DeleteFile(path)
  389.     Raise('Corrupted CD description!\nAborted')
  390.   ENDIF
  391.  
  392.  
  393.   ->-
  394.   ->- pobierz tytuîy poszczególnych utworów
  395.   ->-
  396.  
  397.   FOR x := 0 TO (cdTracks(cd) - 1)
  398.     stringFmt(tmp, 'TTITLE%ld', [x, NIL])
  399.     title := FindToolType(list, tmp)
  400.     IF (title)
  401.       title[StrLen(title) -1] := "\0"
  402.  
  403.       IF (tt_tracktime)
  404.  
  405.         ->-
  406.         ->- dodaj do opisu caîkowity czas trwania pîyty
  407.         ->-
  408.  
  409.         ss, mm := Mod(cdTrackTime(cd, x), 60)
  410.         stringFmt(tmp, '%s [%ld:%02.2ld]\n', [title, mm, ss, NIL])
  411.  
  412.       ELSE
  413.  
  414.         ->-
  415.         ->- tylko track
  416.         ->-
  417.  
  418.         stringFmt(tmp, '%s\n', [title, NIL])
  419.       ENDIF
  420.  
  421.       D('[SAVE] track #\d \s', [x, tmp, NIL])
  422.       Write(handle, tmp, StrLen(tmp))
  423.     ENDIF
  424.   ENDFOR
  425.  
  426.   Close(handle)
  427.   RETURN TRUE
  428.  
  429. EXCEPT
  430.   IF (handle) THEN Close(handle)
  431.   D('[SAVE] error \s\n', [exception, NIL])
  432. ENDPROC FALSE
  433.  
  434.  
  435.  
  436. PROC findmatches(matches:PTR TO lh, buff:PTR TO CHAR, bytes) HANDLE
  437.  
  438.   ->-
  439.   ->- procedura wyciâgajâca informacje o identyfikatorach pîyty
  440.   ->- z bofora odebranych danych
  441.   ->-
  442.  
  443.   DEF par=NIL:PTR TO parser, x, match=NIL: PTR TO match
  444.   DEF name:PTR TO CHAR, category:PTR TO CHAR, tmp[10]:STRING
  445.   DEF list:PTR TO LONG, listlen, rc=TRUE, code
  446.  
  447.   code := Val(buff)
  448.   IF (code = 210)OR(code = 211)
  449.  
  450.     ->-
  451.     ->- multiple matches lub inexact matches
  452.     ->- zamieï na E-LIST
  453.     ->- lista musi mieê przynajmniej 3 pozycje (nagîowek, min. 1 pozycja, kropka koïczâca bufor)
  454.     ->-
  455.  
  456.     list := stringsinfile(buff, bytes, countstrings(buff, bytes))
  457.     listlen := ListLen(list)
  458.     IF (listlen < 3) THEN RETURN FALSE
  459.     NEW par.parser()
  460.  
  461.     ->-
  462.     ->- pobierz dane z bufora (categoria, identyfikator, tytuî)
  463.     ->- pierwsza linia zawiera kod zwrotny, ostatnia zawiera kropkë - moûna je pominâê
  464.     ->-
  465.  
  466.     FOR x := 1 TO (listlen - 2)
  467.       par.parse('CAT,ID,NAME/F', ListItem(list, x))
  468.       category := par.arg(0)
  469.       name     := par.arg(2)
  470.       StrCopy(tmp, '$')
  471.       StrAdd(tmp, par.arg(1))
  472.  
  473.       ->-
  474.       ->- zainicjuj element listy
  475.       ->-
  476.  
  477.       NEW match
  478.       match.category := String(StrLen(category) + 10)
  479.       match.name     := String(StrLen(name) + 10)
  480.       match.cdid     := Val(tmp)
  481.       StrCopy(match.category, category)
  482.       StrCopy(match.name, name)
  483.       AddHead(matches, match)
  484.       D('[FINDMATCH] category \s, cdid $\h\n', [category, Val(tmp), NIL])
  485.     ENDFOR
  486.  
  487.  
  488.   ELSEIF (code = 200)
  489.  
  490.     ->-
  491.     ->- match found
  492.     ->- zdekoduj kategorie pîyty
  493.     ->-
  494.  
  495.     NEW par.parser()
  496.     par.parse('CODE,CAT,ID,NAME/F', buff)
  497.     category := par.arg(1)
  498.     name     := par.arg(3)
  499.     StrCopy(tmp, '$')
  500.     StrAdd(tmp, par.arg(2))
  501.  
  502.     ->-
  503.     ->- zainicjuj element listy
  504.     ->-
  505.  
  506.     NEW match
  507.     match.category := String(StrLen(category) + 10)
  508.     match.name     := String(StrLen(name) + 10)
  509.     match.cdid     := Val(tmp)
  510.     StrCopy(match.category, category)
  511.     StrCopy(match.name, name)
  512.     AddHead(matches, match)
  513.     D('[FINDMATCH] category \s, cdid $\h\n', [category, match.cdid, NIL])
  514.  
  515.   ELSE
  516.  
  517.     ->-
  518.     ->- bîâd odpowiedzi serwera
  519.     ->-
  520.  
  521.     rc := FALSE
  522.   ENDIF
  523.  
  524. EXCEPT DO
  525.   END par
  526. ENDPROC rc
  527.  
  528.  
  529.  
  530. PROC freeallmatches(matches: PTR TO lh)
  531.  
  532.   ->-
  533.   ->- zwalnia pamiëc zajëtâ przez caîâ listë
  534.   ->- nie zwraca ûadnej wartoôci
  535.   ->-
  536.  
  537.   DEF match:PTR TO match
  538.  
  539.   WHILE (match := RemHead(matches)) DO freematch(match)
  540. ENDPROC
  541.  
  542.  
  543.  
  544. PROC freematch(match: PTR TO match)
  545.  
  546.   ->-
  547.   ->- zwalnia pamiëc zajëtâ przez element listy
  548.   ->- nie zwraca ûadnej wartoôci
  549.   ->-
  550.  
  551.   IF (match.category) THEN DisposeLink(match.category)
  552.   IF (match.name) THEN DisposeLink(match.name)
  553.   END match
  554. ENDPROC
  555.